/*
 * casinfo.cpp
 *
 *  Created on: 2016年3月15日
 *      Author: guyadong
 */
#include <string>
#include <sstream>
#include "casinfo.h"
#include "assert_macros.h"
#include "file_utilits.h"
#include "json/json.h"
#include "zlib_wrapper.h"
#include "b64_wrapper.h"
namespace gdface{
/*
 * 从istream中读取分类器
 */
casinfo_cl load_casinfo(std::istream& in,size_t scale_num,float magnify_ratio) {
	casinfo_cl cas;
	cas.level_num=size_t(scale_num);
	cas.magnify_ratio=magnify_ratio;
	in.read((char*) ((&cas.CasNum)), sizeof(int));
	in.read((char*) ((cas.FeaNumPerLayer)), 50 * sizeof(int));
	in.read((char*) ((&cas.FeatherNumPerCas)), sizeof(int));
	// 根据放大级数和FeatherNumPerCas确定特征总数
	cas.Feather = std::vector<feather_cl>(cas.FeatherNumPerCas*scale_num);
	in.read((char*) ((cas.LayerWeight)), 50 * sizeof(double));
	in.read((char*) ((cas.Weight)), 1600 * sizeof(double));
	in.read((char*) cas.Feather.data(), sizeof(feather_cl) * cas.Feather.size());
	for (feather_cl& f : cas.Feather) {
		switch (f.RectangleNum) {
		case 2:
			if (f.Up_Down) {
				f.unitHeight = f.Height / 2;
				f.CorrectNum = f.y + f.unitHeight;
				f.NonfaceCorrectNum = f.y + f.Height;
				f.Valve = f.x + f.Width;
			} else {
				f.unitWidth = f.Width / 2;
				f.CorrectNum = f.x + f.unitWidth;
				f.NonfaceCorrectNum = f.x + f.Width;
				f.Valve = f.y + f.Height;
			}
			break;
		case 3:
			f.unitWidth = f.Width / 3;
			f.unitHeight = (f.Width / 3) * f.Height;
			f.CorrectNum = f.x + f.unitWidth;
			f.NonfaceCorrectNum = f.x + f.unitWidth * 2;
			f.Valve = f.x + f.Width;
			break;
		case 4:
			f.unitHeight = f.Height / 2;
			f.unitWidth = f.Width / 2;
			f.CorrectNum = f.x + f.unitWidth;
			f.NonfaceCorrectNum = f.y + f.unitHeight;
			break;
		default:
			throw std::logic_error(ERROR_STR("invalid RectangleNum"));
		}
	}
	return cas;
}
/*
 * 从文件中读取分类器
 */
casinfo_cl load_casinfo_file(const std::string& file,size_t scale_num,float magnify_ratio) {
	throw_if(file.empty())
	std::istringstream stream(gdface::load_string(file.data()));
	return load_casinfo(dynamic_cast<std::istream&>(stream),scale_num,magnify_ratio);
}

/*
 * 根据放大倍率(magnify_ratio)产生基于feather_src放大的特征,输出到feather_dst
 */
void magnify_feather(feather_cl &feather_dst,const feather_cl &feather_src,double magnify_ratio){
	throw_if(magnify_ratio<=1.0f)
	feather_dst=feather_src; // 先复制所有数据
	feather_dst.x = cl_int(feather_src.x*magnify_ratio+ DETECT_WIN_SCALE_COMP);
	feather_dst.y = cl_int(feather_src.y*magnify_ratio+ DETECT_WIN_SCALE_COMP);
	switch(feather_src.RectangleNum){
	case 2:
		if(feather_src.Up_Down){
			feather_dst.Width	= cl_int(feather_src.Width*magnify_ratio+DETECT_WIN_SCALE_COMP);
			feather_dst.Height	= cl_int(feather_src.Height*magnify_ratio+DETECT_WIN_SCALE_COMP)>>1<<1;
			feather_dst.unitHeight = feather_dst.Height >>1;
			feather_dst.CorrectNum = feather_dst.y + feather_dst.unitHeight;
			feather_dst.NonfaceCorrectNum = feather_dst.y + feather_dst.Height;
			feather_dst.Valve = feather_dst.x + feather_dst.Width;
		}else{
			feather_dst.Width	= cl_int(feather_src.Width*magnify_ratio+DETECT_WIN_SCALE_COMP)>>1<<1;
			feather_dst.Height	= cl_int(feather_src.Height*magnify_ratio+DETECT_WIN_SCALE_COMP);
			feather_dst.unitWidth = feather_dst.Width >>1;
			feather_dst.CorrectNum = feather_dst.x + feather_dst.unitWidth;
			feather_dst.NonfaceCorrectNum = feather_dst.x + feather_dst.Width;
			feather_dst.Valve = feather_dst.y + feather_dst.Height;
		}
		break;
	case 3:
		feather_dst.Width	= cl_int(feather_src.Width*magnify_ratio+DETECT_WIN_SCALE_COMP)/3*3;
		feather_dst.Height	= cl_int(feather_src.Height*magnify_ratio+DETECT_WIN_SCALE_COMP);
		feather_dst.unitWidth = feather_dst.Width / 3;
		feather_dst.unitHeight = (feather_dst.Width / 3) * feather_dst.Height;
		feather_dst.CorrectNum = feather_dst.x + feather_dst.unitWidth;
		feather_dst.NonfaceCorrectNum = feather_dst.x + (feather_dst.unitWidth <<1);
		feather_dst.Valve = feather_dst.x + feather_dst.Width;
		break;
	case 4:
		feather_dst.Width	= cl_int(feather_src.Width*magnify_ratio+DETECT_WIN_SCALE_COMP)>>1<<1;
		feather_dst.Height	= cl_int(feather_src.Height*magnify_ratio+DETECT_WIN_SCALE_COMP)>>1<<1;
		feather_dst.unitHeight = feather_dst.Height >>1;
		feather_dst.unitWidth = feather_dst.Width >>1;
		feather_dst.CorrectNum = feather_dst.x + feather_dst.unitWidth;
		feather_dst.NonfaceCorrectNum = feather_dst.y + feather_dst.unitHeight;
		break;
	default:
		throw std::logic_error(ERROR_STR("invalid RectangleNum"));
	}
	feather_dst.DValve = float(feather_src.DValve*(double(feather_dst.Width*feather_dst.Height)	/ (feather_src.Width*feather_src.Height)));
}
/*
 * 返回根据放大倍率(magnify_ratio)生成的基于feather_src放大特征对象
 */
feather_cl magnify_feather(const feather_cl &feather_src,double magnify_ratio){
	feather_cl feather_dst;
	magnify_feather(feather_dst,feather_src,magnify_ratio);
	return feather_dst;
}
/*
 * 根据放大倍率(magnify_ratio)放大特征数组feather_src,输出到feathers_dst
 * 调用者必须保证feather_src和feather_dst长度必须一致为size
 */
void magnify_feathers_level(feather_cl*feathers_dst,const feather_cl*feather_src,size_t size,double magnify_ratio){
	throw_if(nullptr==feathers_dst||nullptr==feather_src)
	for(decltype(size) i = 0; i < size; ++i){
		magnify_feather(feathers_dst[i],feather_src[i],magnify_ratio);
	}
}
/*
 * 根据放大倍率(magnify_ratio)放大特征数组feather_src,输出到feathers_dst
 */
std::vector<feather_cl> magnify_feathers_level(const feather_cl*feather_src,cl_int size,double magnify_ratio){
	std::vector<feather_cl> feathers_dst(size);
	magnify_feathers_level(feathers_dst.data(),feather_src,size,magnify_ratio);
	return feathers_dst;
}
/*
 * 根据放大级数(level_num)和放大倍率(magnify_ratio)放大特征fv0
 * 返回放大后的所有特征数组
 */
std::vector<feather_cl> magnify_feathers_from0(const feather_cl*fv0_ptr,size_t fv0_size,const measure&m){
	throw_if(nullptr==fv0_ptr||0==fv0_size)
	std::vector<feather_cl> feathers(fv0_size*m.detect_win_size.size());
	// 复制0级特征
	memcpy(feathers.data(),fv0_ptr,fv0_size*sizeof(feather_cl));
	double ratio=1.0;
	// 从第1级(level=1)开始是放大的特征
	for(size_t level=1,level_index=fv0_size; level < m.detect_win_size.size(); ++level,level_index +=fv0_size){
		ratio = std::pow(double(m.step), level);
		magnify_feathers_level(feathers.data()+level_index,fv0_ptr,fv0_size,ratio);
	}
	return feathers;
}
template<typename T>
inline typename std::enable_if<std::is_scalar<T>::value,Json::Value>::type
scalar_to_jsonarray(T* ptr,size_t size){
	throw_if(nullptr==ptr)
	Json::Value value;
	for(decltype(size) i=0;i<size;++i){
		value.append(ptr[i]);
	}
	return value;
}
void jsonarray_to_array(const Json::Value &value, int *ptr, size_t size) {
	throw_if(nullptr == ptr)
		throw_if(!value.isArray())
		throw_if(value.size() != size)
		for (decltype(size) i = 0; i<size; ++i) {
			ptr[i] = value[int(i)].asInt();
		}
}

void jsonarray_to_array(const Json::Value &value,double *ptr,size_t size){
	throw_if(nullptr==ptr)
	throw_if(!value.isArray())
	throw_if(value.size()!=size)
	for(decltype(size) i=0;i<size;++i){
		ptr[i]=value[int(i)].asDouble();
	}
}
inline Json::Value feather_vector_to_jsonarray(const feather_cl*feathers,size_t size){
	Json::Value value;
	for(decltype(size) i=0;i<size;++i){
		auto feather=feathers[i];
		Json::Value json_feather;
		json_feather["x"]=feather.x;
		json_feather["y"]=feather.y;
		json_feather["Width"]=feather.Width;
		json_feather["Height"]=feather.Height;
		json_feather["Up_Down"]=feather.Up_Down;
		json_feather["RectangleNum"]=feather.RectangleNum;
		json_feather["Valve"]=feather.Valve;
		json_feather["DValve"]=feather.DValve;
		json_feather["Sign"]=feather.Sign;
		json_feather["CorrectNum"]=feather.CorrectNum;
		json_feather["NonfaceCorrectNum"]=feather.NonfaceCorrectNum;
		json_feather["unitWidth"]=feather.unitWidth;
		json_feather["unitHeight"]=feather.unitHeight;
		value.append(json_feather);
	}
	return value;
}
inline std::vector<feather_cl> jsonarray_to_feather_vector(const Json::Value &value){
	throw_if(!value.isArray())
	std::vector<feather_cl>feathers(value.size());
	for(decltype(value.size()) i=0;i<value.size();++i){
		feathers[i].x				=value[i]["x"].asInt();
		feathers[i].y				=value[i]["y"].asInt();
		feathers[i].Width		=value[i]["Width"].asInt();
		feathers[i].Height		=value[i]["Height"].asInt();
		feathers[i].Up_Down	=value[i]["Up_Down"].asInt();
		feathers[i].RectangleNum=value[i]["RectangleNum"].asInt();
		feathers[i].Valve		=value[i]["Valve"].asInt();
		feathers[i].DValve		=value[i]["DValve"].asFloat();
		feathers[i].Sign			=value[i]["Sign"].asInt();
		feathers[i].CorrectNum=value[i]["CorrectNum"].asInt();
		feathers[i].NonfaceCorrectNum=value[i]["NonfaceCorrectNum"].asInt();
		feathers[i].unitWidth	=value[i]["unitWidth"].asInt();
		feathers[i].unitHeight=value[i]["unitHeight"].asInt();
	}
	return feathers;
}

/* 将 casinfo_cl 对象保存为json对象
 * full为true时保存所有级别的分类器，为false时只保存0级分类器
 *  */
Json::Value casinfo_to_json(const casinfo_cl&cas,bool full=false){
	Json::Value root;
	// 分类器总数必须是FeatherNumPerCas的倍数，否则抛出异常
	throw_except_if_msg(face_exception, cas.Feather.size() % cas.FeatherNumPerCas, "invalid feathers number")
	root["CasNum"]=cas.CasNum;
	root["FeaNumPerLayer"]=scalar_to_jsonarray(cas.FeaNumPerLayer,cas.CasNum);
	root["Weight"]=scalar_to_jsonarray(cas.Weight,cas.FeatherNumPerCas);
	root["LayerWeight"]=scalar_to_jsonarray(cas.LayerWeight,cas.CasNum);
	root["FeatherNumPerCas"]=cas.FeatherNumPerCas;
	root["Feather"]=feather_vector_to_jsonarray(cas.Feather.data(),full?cas.Feather.size():cas.FeatherNumPerCas);
	// 保存多级分类器时，指定多级分类器的放大倍率
	if (full&&cas.Feather.size() > size_t(cas.FeatherNumPerCas)) {
		root["magnify_ratio"] = cas.magnify_ratio;
	}
	return root;
}
/* 从json对象中解析出数据生成casinfo_cl对象 */
casinfo_cl json_to_casinfo(const Json::Value &root){
	casinfo_cl cas;
	cas.CasNum=root["CasNum"].asInt();
	cas.FeatherNumPerCas=root["FeatherNumPerCas"].asInt();
	throw_except_if_msg(face_exception,cas.CasNum>MAX_LAYER_NUM,"invalid CasNum")
	throw_except_if_msg(face_exception,cas.FeatherNumPerCas>MAX_WEIGHT_NUM,"invalid FeatherNumPerCas")
	jsonarray_to_array(root["FeaNumPerLayer"],cas.FeaNumPerLayer,cas.CasNum);
	jsonarray_to_array(root["Weight"],cas.Weight,cas.FeatherNumPerCas);
	jsonarray_to_array(root["LayerWeight"],cas.LayerWeight,cas.CasNum);
	cas.Feather=jsonarray_to_feather_vector(root["Feather"]);
	// 分类器总数必须是FeatherNumPerCas的倍数，否则抛出异常
	throw_except_if_msg(face_exception, cas.Feather.size() % cas.FeatherNumPerCas, "invalid feathers total number")
	cas.level_num=cas.Feather.size()/cas.FeatherNumPerCas;
	// 有多级分类器时，json中必须定义放大倍率magnify_ratio，否则抛出异常
	if (cas.level_num > 1) {
		auto ratio = root["magnify_ratio"];
		throw_except_if_msg(face_exception, Json::Value::nullRef==ratio , "'magnify_ratio' not defined");
		cas.magnify_ratio = ratio.asFloat();
	}		
	return cas;
}
/* 将 casinfo_cl 对象保存为json字符串输出到ostream对象
 * full为false时只保存0级分类器
 * fast为false时，输出格式化的json字符串
 * */
void save_casinfo_json(const casinfo_cl&cas, std::ostream &stream, bool fast,bool full) {
	Json::Value root = casinfo_to_json(cas,full);
	if (fast) {
		stream << Json::FastWriter().write(root);
	}else {
		stream << root.toStyledString() << std::endl;
	}
}
/* 从字符串中解析json对象，生成casinfo_cl对象 */
casinfo_cl load_casinfo_json(const std::string& json){
	throw_if(json.empty())
	std::cout<<"parse casinfo from  json string..."<<std::endl;
	Json::Reader reader;
	Json::Value root;
	 if (reader.parse(json, root)) {
		 return json_to_casinfo(root);
	 }
	throw face_exception(ERROR_STR(" fail to parse json"));
}
/* 从压缩的base64编码字符串中解析出json对象，生成casinfo_cl对象
 * uncompress_bound为压缩前的数据长度,如果不知道数据源长度设置为0
 * */
casinfo_cl load_casinfo_json_compressed(const void* json_compressed_ptr,size_t length,size_t uncompress_bound){
	std::string json;
	{
		auto v=zlib::mem_uncompress(json_compressed_ptr,length,uncompress_bound);
		json=std::string(reinterpret_cast<char*>(v.data()),v.size());
	}
	return load_casinfo_json(json);
}
/* 从压缩的base64编码字符串中解析出json对象，生成casinfo_cl对象
 * uncompress_bound为压缩前的数据长度,如果不知道数据源长度设置为0
 * */
casinfo_cl load_casinfo_json_compressed_base64(const std::string& json_compressed_base64,size_t uncompress_bound){
	auto compressed_json=base64::decode(json_compressed_base64);
	return load_casinfo_json_compressed(compressed_json.data(),compressed_json.size(),uncompress_bound);
}

/* 以json格式从文件中解析数据生成 casinfo_cl */
casinfo_cl load_casinfo_json_file(const std::string& file){
	throw_if(file.empty())
	std::cout<<"load casinfo json file:"<<file<<std::endl;
	return load_casinfo_json(load_string(file.data()));
}
/* casinfo_cl 转为json字符串
 * full为false时只保存0级分类器
 * compressed为true对json字符串进行压缩
 * base64为true时将压缩的字符串转为base64编码字符串
 * */
std::string casinfo_to_json_str(const casinfo_cl& cas,bool full,bool compressed,bool base64) {
	std::ostringstream stream;
	save_casinfo_json(cas, dynamic_cast<std::ostream &>(stream), false,full);
	std::string json_str=stream.str();
	if(!compressed)
		return json_str;
	auto compressed_json= zlib::mem_compress(json_str);
	if(!base64)
		return std::string((char*)compressed_json.data(),compressed_json.size());
	return base64::encode(compressed_json.data(), compressed_json.size());
}
/* 以json格式保存casinfo_cl对象到文件
 * full为false时只保存0级分类器
 * */
void save_casinfo_json_file(const casinfo_cl& cas, const std::string& file,bool full) {
	throw_if(file.empty())
	std::string json_str= casinfo_to_json_str(cas,full);
	save_binary_file(file.data(), (const uint8_t*)json_str.data(), json_str.size());
}
casinfo_cl& casinfo_cl::build_feathers(const measure&m) {
	this->Feather = magnify_feathers_from0(this->Feather.data()
			, this->FeatherNumPerCas
			, m);
	this->level_num=m.detect_win_size.size();
	this->magnify_ratio=m.step;
	return *this;
}
inline feather_short_cl convert_short(const feather_cl&feather){
	return {
		 feather.DValve
		,cl_short(feather.x)
		,cl_short(feather.y)
		,cl_short(feather.Width)
		,cl_short(feather.Height)
		,cl_short(feather.Up_Down)
		,cl_short(feather.Valve)
		,cl_short(feather.CorrectNum)
		,cl_short(feather.NonfaceCorrectNum)
		,cl_short(feather.unitWidth)
		,cl_short(feather.unitHeight)
		,cl_char(feather.Sign)
		,cl_uchar(feather.RectangleNum)};
}
std::vector<feather_short_cl> convert_short(const std::vector<feather_cl>&feathers){
	auto feathers_short=std::vector<feather_short_cl>(feathers.size());
	for(size_t i=0;i<feathers_short.size();++i)	feathers_short[i]=convert_short(feathers[i]);
	return feathers_short;
}
casinfo_base_float to_casinfo_base_float(const casinfo_base& cas) {
	casinfo_base_float cas_float;
	cas_float.CasNum = cas.CasNum;
	cas_float.FeatherNumPerCas = cas.FeatherNumPerCas;
	memcpy(cas_float.FeaNumPerLayer, cas.FeaNumPerLayer, sizeof(cas_float.FeaNumPerLayer) * MAX_LAYER_NUM);
	for (int i = 0; i < MAX_WEIGHT_NUM; ++i) {
		cas_float.Weight[i] = float(cas.Weight[i]);
	}
	for (int i = 0; i < MAX_LAYER_NUM; ++i) {
		cas_float.LayerWeight[i] = float(cas.LayerWeight[i]);
	}
	return cas_float;
}

}/* namespace gdface */
